unit testcase;

interface

uses Windows, IfxConnection;

type

  TLogEvent = procedure (const Message: string) of object;

  TCheckProc = procedure of object;

  TNewFeatures117 = class
  private
    FConnection: TIfxConnection;
    FOnLog: TLogEvent;
    FGuid: string;

    procedure Log(const Message: string);

    procedure Connect;
    procedure Disconnect;
    procedure CreateTestTable;
    procedure Execute(const SQL: string);
    function GetCountOfGuid: Integer;
    procedure StartTrans;
    procedure Commit;
    procedure Rollback;
    function GenerateNewGUID: string;
    procedure InsertGuid;

    procedure CreateTables;

    procedure Check_Commit_AnsiDatabase;
    procedure Check_Rollback_AnsiDatabase;

    procedure Check_CommitOnClose_Buffered;
    procedure Check_RollbackOnClose_Buffered;

    procedure Check_CommitOnClose_AnsiDatabase;
    procedure Check_RollbackOnClose_AnsiDatabase;

    procedure Check_IsTransactionsSupported_and_IsAnsiDatabase;

    procedure Check_CommitRetain;

    procedure Check_AnsiAutoCommit;

    procedure DropDatabases;

    procedure ExecCheck(Proc: TCheckProc);

  public
    constructor Create;
    destructor Destroy; override;
    procedure Run;
    property Connection: TIfxConnection read FConnection;
    property OnLog: TLogEvent read FOnLog write FOnLog;
  end;

const
  BoolToStr: array [Boolean] of string = ('False', 'True');
  TransactionActionToStr: array [TIfxTransactionAction] of string = ('Commit', 'Rollback');

implementation

uses SysUtils, ActiveX, ComObj, Ifx, IfxSQL;

{ TNewFeatures117 }

constructor TNewFeatures117.Create;
begin
  inherited;
  FConnection := TIfxConnection.Create(nil);
  FConnection.GetInformixEnvironment(FConnection.Params);
end;

destructor TNewFeatures117.Destroy;
begin
  FConnection.Free;
  inherited;
end;

procedure TNewFeatures117.Log(const Message: string);
begin
  if Assigned(FOnLog) then FOnLog(Message);
end;

function TNewFeatures117.GetCountOfGuid: Integer;
var
  IfxSQL: TIfxSQL;
begin
  IfxSQL := TIfxSQL.Create(nil);
  with IfxSQL do
  begin
    try
      Connection := FConnection;
      SQL.Text := 'select count(*) from test where fld = :fld';
      ParamByName('fld').AsString := FGuid;
      Open;
      Result := Fields[0].AsInteger;
    finally
      Free;
    end;
  end;
end;

procedure TNewFeatures117.Connect;
begin
  FConnection.LoginPrompt := False;
  FConnection.Open;
end;

procedure TNewFeatures117.Disconnect;
begin
  FConnection.Close;
end;

procedure TNewFeatures117.CreateTestTable;
begin
  try
    Execute('drop table test');
  except
  end;
  Execute('create table test (fld char(38))');
end;

procedure TNewFeatures117.StartTrans;
begin
  FConnection.StartTransaction;
end;

procedure TNewFeatures117.Commit;
begin
  FConnection.Commit;
end;

procedure TNewFeatures117.Execute(const SQL: string);
begin
  FConnection.Execute(SQL);
end;

procedure TNewFeatures117.CreateTables;
begin
  Log('CreateTables');

  FConnection.Params.Values['DATABASE'] := '';
  Connect;

  FConnection.AnsiAutoCommit := True;
  FConnection.Execute('create database ansi_test with log mode ansi');
  CreateTestTable;

  FConnection.Execute('create database buffered_test with buffered log');
  CreateTestTable;

  FConnection.Execute('create database nolog_test');
  CreateTestTable;

  Disconnect;

  Log('SUCCEEDED'#13#10);
end;

procedure TNewFeatures117.Check_Commit_AnsiDatabase;
begin
  Log('Check_Commit_AnsiDatabase');

  FConnection.Params.Values['DATABASE'] := 'ansi_test';
  FConnection.AnsiAutoCommit := True;
  Connect;
  StartTrans;
  InsertGuid;
  Commit;
  Disconnect;

  FConnection.AnsiAutoCommit := False;
  Connect;
  if GetCountOfGuid <> 1 then
    raise Exception.Create('Commit failed');
  Disconnect;

  Log('SUCCEEDED'#13#10);
end;

procedure TNewFeatures117.Check_Rollback_AnsiDatabase;
begin
  Log('Check_Rollback_AnsiDatabase');

  FConnection.Params.Values['DATABASE'] := 'ansi_test';
  FConnection.AnsiAutoCommit := False;
  Connect;
  Commit;
  StartTrans;
  InsertGuid;
  Rollback;
  Disconnect;

  FConnection.AnsiAutoCommit := False;
  Connect;
  if GetCountOfGuid <> 0 then
    raise Exception.Create('Rollback failed');
  Disconnect;

  Log('SUCCEEDED'#13#10);
end;

procedure TNewFeatures117.Check_CommitOnClose_Buffered;
begin
  Log('Check_CommitOnClose_Buffered');

  FConnection.Params.Values['DATABASE'] := 'buffered_test';
  FConnection.TransactionActionOnClose := taCommit;
  FConnection.AnsiAutoCommit := False;
  Connect;
  Execute('begin work');
  InsertGuid;
  Disconnect;

  FConnection.CommitRetain := True;
  Connect;
  if GetCountOfGuid <> 1 then
    raise Exception.Create('Commit on close failed');
  Disconnect;

  Log('SUCCEEDED'#13#10);
end;

procedure TNewFeatures117.Check_RollbackOnClose_Buffered;
begin
  Log('Check_RollbackOnClose_Buffered');

  FConnection.Params.Values['DATABASE'] := 'buffered_test';
  FConnection.TransactionActionOnClose := taRollback;
  FConnection.AnsiAutoCommit := False;
  Connect;
  Execute('begin work');
  InsertGuid;
  Disconnect;

  FConnection.CommitRetain := True;
  Connect;
  if GetCountOfGuid > 0 then
    raise Exception.Create('Rollback on close failed');
  Disconnect;

  Log('SUCCEEDED'#13#10);
end;

procedure TNewFeatures117.Check_CommitOnClose_AnsiDatabase;
begin
  Log('Check_CommitOnClose_AnsiDatabase');

  FConnection.Params.Values['DATABASE'] := 'ansi_test';
  FConnection.TransactionActionOnClose := taCommit;
  FConnection.AnsiAutoCommit := False;
  Connect;
  InsertGuid;
  Disconnect;

  FConnection.AnsiAutoCommit := True;
  FConnection.CommitRetain := True;
  Connect;
  if GetCountOfGuid <> 1 then
    raise Exception.Create('Commit on close failed');
  Disconnect;

  Log('SUCCEEDED'#13#10);
end;

procedure TNewFeatures117.Check_RollbackOnClose_AnsiDatabase;
begin
  Log('Check_RollbackOnClose_AnsiDatabase');

  FConnection.Params.Values['DATABASE'] := 'ansi_test';
  FConnection.TransactionActionOnClose := taRollback;
  FConnection.AnsiAutoCommit := False;
  Connect;
  InsertGuid;
  Disconnect;

  FConnection.CommitRetain := True;
  Connect;
  if GetCountOfGuid > 0 then
    raise Exception.Create('Rollback on close failed');
  Disconnect;

  Log('SUCCEEDED'#13#10);
end;

procedure TNewFeatures117.Check_IsTransactionsSupported_and_IsAnsiDatabase;
begin
  Log('Check_IsTransactionsSupported_and_IsAnsiDatabase');

  FConnection.Params.Values['DATABASE'] := 'ansi_test';
  Connect;
  if not FConnection.IsTransactionsSupported or not FConnection.IsAnsiDatabase then
    raise Exception.Create('Failed on ansi_test database');
  Disconnect;

  FConnection.Params.Values['DATABASE'] := 'buffered_test';
  Connect;
  if not FConnection.IsTransactionsSupported or FConnection.IsAnsiDatabase then
    raise Exception.Create('Failed on buffered_test database');
  Disconnect;

  FConnection.Params.Values['DATABASE'] := 'nolog_test';
  Connect;
  if FConnection.IsTransactionsSupported or FConnection.IsAnsiDatabase then
    raise Exception.Create('Failed on nolog_test database');
  Disconnect;

  Log('SUCCEEDED'#13#10);
end;

procedure TNewFeatures117.Check_CommitRetain;

  procedure SelectSomeData;
  begin
    with TIfxSQL.Create(nil) do
      try
        Connection := FConnection;
        SQL.Text := 'select * from informix.systables';
        Open;
        Commit;
        Next;
      finally
        Free;
      end;
  end;

begin
  Log('Check_CommitRetain');

  FConnection.Params.Values['DATABASE'] := 'ansi_test';
  FConnection.AnsiAutoCommit := True;

  FConnection.CommitRetain := True;
  Connect;
  SelectSomeData;
  Disconnect;

  FConnection.CommitRetain := False;
  Connect;
  try
    SelectSomeData;
    raise Exception.Create('CommitRetain is false but cursor are alive after commit');
  except
    on E: EIfxError do
      { -400 exception must be }
      if E.SQL <> -400 then raise;
  end;
  Disconnect;

  Log('SUCCEEDED'#13#10);
end;

procedure TNewFeatures117.Check_AnsiAutoCommit;
var
  IfxSQL: TIfxSQL;
  Count: Integer;
begin
  Log('Check_AnsiAutoCommit');

  FConnection.Params.Values['DATABASE'] := 'ansi_test';
  FConnection.AnsiAutoCommit := True;

  Connect;
  InsertGuid;
  Rollback;

  StartTrans;
  IfxSQL := TIfxSQL.Create(nil);
  with IfxSQL do
    try
      Connection := FConnection;
      SQL.Text := 'select count(*) from test where fld = :fld';
      ParamByName('fld').AsString := FGuid;
      Open;
      Count := Fields[0].AsInteger;
    finally
      Free;
    end;
  Commit;

  Disconnect;

  if Count <> 1 then
    raise Exception.Create('Data was not commited');


  FConnection.Params.Values['DATABASE'] := 'ansi_test';
  FConnection.AnsiAutoCommit := False;

  Connect;
  InsertGuid;
  Rollback;

  StartTrans;
  IfxSQL := TIfxSQL.Create(nil);
  with IfxSQL do
    try
      Connection := FConnection;
      SQL.Text := 'select count(*) from test where fld = :fld';
      ParamByName('fld').AsString := FGuid;
      Open;
      Count := Fields[0].AsInteger;
    finally
      Free;
    end;
  Commit;

  Disconnect;

  if Count <> 0 then
    raise Exception.Create('Data was not rolled back');

  Log('SUCCEEDED'#13#10);
end;

procedure TNewFeatures117.DropDatabases;

  procedure DropDatabase(const Name: string);
  begin
    try
      FConnection.Execute('drop database ' + Name);
    except
      on E: EIfxError do
        if E.SQL <> -329 then raise;
    end;
  end;

begin
  FConnection.Params.Values['DATABASE'] := '';
  Connect;
  DropDatabase('ansi_test');
  DropDatabase('buffered_test');
  DropDatabase('nolog_test');
  Disconnect;
end;

procedure TNewFeatures117.ExecCheck(Proc: TCheckProc);
begin
  try
    Proc;
  except
    on E: Exception do
      Log('FAILED with error:'#13#10 + E.Message + #13#10);
  end;
end;

procedure TNewFeatures117.Run;
var
  StartTickCount: DWORD;
begin
  StartTickCount := GetTickCount;
  Log('START'#13#10);
  try
    DropDatabases;
    ExecCheck(CreateTables);
    ExecCheck(Check_Commit_AnsiDatabase);
    ExecCheck(Check_Rollback_AnsiDatabase);
    ExecCheck(Check_CommitOnClose_Buffered);
    ExecCheck(Check_RollbackOnClose_Buffered);
    ExecCheck(Check_CommitOnClose_AnsiDatabase);
    ExecCheck(Check_RollbackOnClose_AnsiDatabase);
    ExecCheck(Check_IsTransactionsSupported_and_IsAnsiDatabase);
    ExecCheck(Check_CommitRetain);
    ExecCheck(Check_AnsiAutoCommit);
    DropDatabases;
    Log(Format('DONE in %d ms', [GetTickCount - StartTickCount]));
  except
    on E: Exception do
      Log('FAILED with error:'#13#10 + E.Message);
  end;
end;

procedure TNewFeatures117.Rollback;
begin
  FConnection.Rollback;
end;

function TNewFeatures117.GenerateNewGUID: string;
var
  Guid: TGuid;
begin
  OleCheck(CoCreateGuid(Guid));
  FGuid := GUIDToString(Guid);
  Result := FGuid;
end;

procedure TNewFeatures117.InsertGuid;
begin
  Execute(Format('insert into test values (''%s'')', [GenerateNewGUID]));
end;

end.
